Clear stamped code-block height when Hide Info collapses a tool call - #5924
Conversation
The scrollBottomIntoView modifier on a tool call's code block stamped an inline pixel height sized to the Monaco editor's content, but nothing ever cleared it. When a tool-call message mounted while its code area was already expanded (reopening the AI assistant panel, re-entering the room, a submode switch), the modifier stamped the height at install; a later "Hide Info" removed the editor but left the container at its expanded size, leaving an empty gap below the header. Make the modifier consume isDisplayingCode so it re-runs on toggle, and reset the inline height on the collapse / no-measurable-editor paths so the block returns to its header-only height. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Preview deploymentsHost Test Results 1 files ±0 1 suites ±0 1h 58m 34s ⏱️ - 2m 48s Results for commit 1410aca. ± Comparison against earlier commit 176c4ea. Realm Server Test Results 1 files ±0 1 suites ±0 19m 25s ⏱️ +32s Results for commit 1410aca. ± Comparison against earlier commit 176c4ea. |
backspace
left a comment
There was a problem hiding this comment.
[Claude Code 🤖]
I went after what changes on the paths this modifier previously never ran on — expand, remount, rebuild — and checked the height math against the code block's own CSS; I did not exercise it in a browser.
The collapse fix is correct and the remount reproduction in the test is real. But consuming isDisplayingCode also activates the height stamp on the expand path, where getContentHeight() over-measures anything past the editor's 250px cap — so for long tool calls this moves the empty block from "Hide Info" to "View Info". That is the one blocking item.
- Drop the outer height stamp, or measure the editor's rendered box instead of its content height — see the
scrollBottomIntoViewthread. Blocking. - Confirm you want "View Info" to scroll the panel; that behavior falls out of the same change — same thread. Needs an answer, not a change.
- Add expanded-state coverage with a payload past the cap — see the tools-test thread. Non-blocking.
Percy is the only non-green check, with 2 unreviewed visual changes. Worth opening rather than bulk-approving, since this change can alter the code block's box height.
| let editor = this.args.monacoSDK.editor | ||
| .getEditors() | ||
| .find((editor) => element.contains(editor.getContainerDomNode())); | ||
| let editorHeight = editor?.getContentHeight() ?? 0; |
There was a problem hiding this comment.
[Claude Code 🤖]
Consuming isDisplayingCode also makes the expand path stamp a height for the first time, and this math over-measures — so as written the PR trades an empty block after "Hide Info" for one after "View Info".
getContentHeight() is Monaco's full content height, but .code-block-editor is capped at --code-block-max-height (250px) in ai-assistant/code-block/index.gts, and the outer .code-block section has no max-height of its own, only overflow: hidden. The stamp is therefore header + contentHeight while the box renders header + min(contentHeight, 250). Monaco's line height here is 1.5 × 12px on macOS (1.35 × elsewhere) plus 16px of padding, so past ~13 lines of tool-call JSON — routine for a patchCardInstance patch or a search filter — expanding leaves a contentHeight − 250 gap. The // max-height is constrained by CSS note on the stamp is what makes it read as safe; that cap is on the child, not on element.
It only bites now because expand previously never re-ran the modifier. And the editor really is measurable on that re-run: Glimmer runs scheduled modifier installs before scheduled updates within one commit, so the freshly created Monaco editor already reports a content height when this update lands.
The stamp is also redundant — the Monaco modifier sizes the editor div and CSS clamps it, so header + renderedEditorHeight is the section's natural height. Dropping it removes both the over-stamp and the need to clear anything:
private scrollBottomIntoView = modifier((element: HTMLElement) => {
// Consume the toggle flag so this re-runs when the code area opens.
if (!this.isDisplayingCode) {
return;
}
this.scrollIntoView(element.parentElement as HTMLElement);
});To keep the stamp instead, measure the rendered box: editor?.getContainerDomNode().offsetHeight in place of getContentHeight().
Either shape carries one decision: expand now reaches scrollIntoView, which it never did on a normal mount, so clicking "View Info" on a message up in the scrollback will scroll the panel. Likely the modifier's original intent, but it is new user-visible behavior — worth confirming you want it.
Regression introduced here, on top of a calculation that was previously only reachable through the remount path. Blocking.
There was a problem hiding this comment.
[Claude Code 🤖]
Agreed — real regression, and it's now fixed by dropping the outer height stamp entirely (1410aca). The Monaco modifier already sizes .code-block-editor and CSS caps it at 250px, so the section sizes to its content: no over-measure on expand, and nothing to clear on collapse.
Context that argues for removing it rather than patching the math — the stamp predates the self-sizing editor. It was added in Dec 2024 when the code rendered into a plain monaco-container with no height of its own, so back then the stamp was the only thing giving the code area a size. The self-sizing editor (onDidContentSizeChange) arrived with the CodeBlock refactor in #2859 (Jul 2025), which made the stamp redundant; it just survived the refactor still reading Monaco's uncapped content height. So this removes a leftover, not a safeguard.
On scroll-on-expand: confirmed intentional. "View Info" now brings the code into view, which matches the modifier's original purpose — keeping it.
| let codeBlock = find( | ||
| '[data-test-tool-call-id="hide-info-height"] .tool-code-block', | ||
| ) as HTMLElement; | ||
| assert.ok(codeBlock, 'tool code block element exists'); | ||
| assert.strictEqual( | ||
| codeBlock.style.height, | ||
| '', | ||
| 'inline height is cleared so the block collapses to its header-only height', | ||
| ); |
There was a problem hiding this comment.
[Claude Code 🤖]
This pins the collapsed state but not the expanded one, which is where the height math is now newly exercised. The payload here renders 13 lines, just under the 250px editor cap, so it cannot distinguish a correct stamp from an over-stamp.
Add a case whose tool-call payload exceeds --code-block-max-height and assert, while expanded, that the section's height is no greater than the header plus the editor's rendered height. Against the current diff that fails — see the scrollBottomIntoView thread.
Smaller, on these lines: find(...) as HTMLElement is dereferenced immediately after a soft assert.ok, so a null match both fails an assertion and throws; and .tool-code-block carries no CSS rule anywhere in the repo, making it an invisible test-only hook nothing protects. An assert.dom(...).exists() before the read covers the first, and a data-test- attribute alongside the class would make the hook explicit.
Non-blocking; the coverage half is what would have caught the expand-path issue.
There was a problem hiding this comment.
[Claude Code 🤖]
Done:
- Added
expanding a tall tool call does not leave an empty gap below the code— a 30-line (over-cap) payload asserting that, while expanded, the section height doesn't exceed the sum of its rendered children (and carries no inline height). That fails against the old stamp and locks in the content-sizing behavior. - The collapse assertion now does
assert.dom(...).exists()before dereferencing, so a null match fails cleanly instead of throwing. - Replaced the class-only
.tool-code-blockhook with an explicitdata-test-tool-code-blockattribute on the CodeBlock.
…ight Drop the inline pixel height the scrollBottomIntoView modifier stamped on the code block. The Monaco modifier already sizes the editor and CSS caps it, so the section sizes to its content naturally: the block collapses back to its header when the editor is removed, and it no longer over-measures on expand. The previous approach measured Monaco's uncapped content height, which exceeds the editor's 250px cap for long payloads, so it would have left an empty gap below the code when expanding a tall tool call. The modifier now only brings the code into view when it opens. Add coverage for a tall (over-cap) payload asserting the expanded block does not exceed its rendered children, and give the block an explicit test hook. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
[Claude Code 🤖] CI is green — all 16 Host Test shards pass with the new coverage, plus Lint / Realm / Matrix / Boxel CLI. The only non-pass is the Percy visual gate (1 change needs review), expected since the code block's rendered height changes; opening it for review rather than bulk-approving, per your note. |
Problem
In an AI assistant room, expanding a completed tool call's code (ⓘ → "View Info") and then clicking "Hide Info" intermittently left a large empty area below the tool-call header. The Monaco editor was removed from the DOM but the container kept its expanded height.
Root cause
The
scrollBottomIntoViewmodifier on the tool call's<CodeBlock>stamps an inline pixel height on the container sized to the editor's content:Nothing ever cleared it. The functional modifier consumed no tracked state that changes on toggle, so it only ran at install:
getContentHeight()→ 0, early return) — no height is stamped and collapse works.The inner editor div already self-sizes (the
monaco-editormodifier sets and updates its height and CSS caps it), so the outer-container stamp is only for snug fit + scroll-into-view.Fix
Make the modifier consume
isDisplayingCodeso it re-runs on toggle, and reset the inline height on the collapse / no-measurable-editor paths so the container returns to its header-only height.Test
Adds an integration test that reproduces the remount-while-open condition (close + reopen the AI assistant panel with the code area expanded) and asserts that after "Hide Info" the editor is gone and the container has no leftover inline height.
Verification
findtest helper import).